using System.Collections.Generic;
using UnityEngine;
using XNode;

namespace AI.FSM.Builder
{
    [NodeTint("#2e506b")]
    public abstract class FSMStateGraphNode : FSMGraphNode
    {

        internal bool IsEnter 
        {
            set => isEnter = value;
            get => isEnter;
        }

        internal bool IsExit => isExit;

        internal virtual void Build<T>(ref int nextIndex,List<FSMState<T>> states,Dictionary<int,int> nodeIdToStateIndexMap)
        {
            var instanceId = GetInstanceID();
            if(nodeIdToStateIndexMap.ContainsKey(instanceId))
            {
                return;
            }
            nodeIdToStateIndexMap[instanceId] = nextIndex;
            nextIndex ++;
            var state = CreateState<T>();
            states.Add(state);
            state.Transitions = BuildTransition(ref nextIndex,states,nodeIdToStateIndexMap);
        }

        protected virtual FSMTransition<T>[] BuildTransition<T>(ref int nextIndex,List<FSMState<T>> states,Dictionary<int,int> nodeIdToStateIndexMap)
        {
            var transitions = new List<FSMTransition<T>>();
            for (int i = 0; i < transitionsCount; i++)
            {
                var transition = GetTransitionNode(i);
                var targetState = transition.GetTransitionState();
                if(targetState == null) continue;
                if(nodeIdToStateIndexMap.TryGetValue(targetState.GetInstanceID(),out var targetIndex) == false)
                {
                    targetState.Build(ref nextIndex,states,nodeIdToStateIndexMap);
                    targetIndex = nodeIdToStateIndexMap[targetState.GetInstanceID()];
                }

                transitions.Add(transition.Build<T>(targetIndex));
            }
            return transitions.ToArray();
        }

        protected FSMTransitionGraphNode GetTransitionNode(int index)
        {
            var port = GetOutputPort($"transition {index}");
            return (FSMTransitionGraphNode)port?.Connection?.node;
        }

        protected abstract FSMState<T> CreateState<T>();

        [HideInInspector, SerializeField]
        bool isEnter;

        [HideInInspector, SerializeField]
        bool isExit;
        int transitionsCount;
    }
}